package com.lagou.edu.factory;

import net.sf.cglib.core.ReflectUtils;

import org.dom4j.DocumentException;
import com.alibaba.druid.util.StringUtils;
import com.lagou.edu.annotation.Autowired;
import com.lagou.edu.annotation.Service;
import com.lagou.edu.annotation.Transactional;
import org.reflections.Reflections;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * @author 应癫
 *
 * 工厂类，生产对象（使用反射技术）
 */
public class BeanFactory {

    /**
     * 任务一：读取解析xml，通过反射技术实例化对象并且存储待用（map集合）
     * 任务二：对外提供获取实例对象的接口（根据id获取）
     */

    private static Map<String,Object> map = new HashMap<>();  // 存储对象


    static {
        // 任务一：读取解析xml，通过反射技术实例化对象并且存储待用（map集合）

        try {

            // 任务一：扫描包，分析需实例化的对象列表（service和事务管理器）,通过反射技术实例化对象并且存储待用（map集合）
            //扫描com.lagou.edu下所有被Service声明的类的集合
            Reflections f = new Reflections("com.lagou.edu");
            Set<Class<?>> set = f.getTypesAnnotatedWith(Service.class);

            for (Class<?> c : set) {
                //获取对象的实例
                Object bean = c.newInstance();
                Service annotation = c.getAnnotation(Service.class);
                //设置key，对象的key在service注解有value使用value，没有value使用类名
                if(StringUtils.isEmpty(annotation.value())){
                    String[] names = c.getName().split("\\.");
                    map.put(names[names.length-1], bean);
                }else{
                    map.put(annotation.value(), bean);
                }
            }
            //完成实例化后，检查被Autowired修饰的字段，并进行填充
            for(Map.Entry<String, Object> entry:map.entrySet()){
                Object o = entry.getValue();
                Class c = o.getClass();
                Field[] fields = c.getDeclaredFields();
                for (Field field : fields) {
                    if (field.isAnnotationPresent(Autowired.class)
                            &&field.getAnnotation(Autowired.class).required()) {
                        String[] names = field.getType().getName().split("\\.");
                        String name = names[names.length-1];
                        Method[] methods = c.getMethods();
                        for (int j = 0; j < methods.length; j++) {
                            Method method = methods[j];
                            if(method.getName().equalsIgnoreCase("set" + name)) {
                                method.invoke(o,map.get(name));
                            }
                        }
                    }
                }
                //判断对象是否有Transactional注解，如果有则修改对象为代理对象
                if(c.isAnnotationPresent(Transactional.class)){

                    ProxyFactory proxyFactory = (ProxyFactory) BeanFactory.getBean("proxyFactory");
                    //判断是否实现接口
                    Class[] face = c.getInterfaces();
                    if(face!=null&&face.length>0){
                        o = proxyFactory.getJdkProxy(o);
                    }else{
                        o = proxyFactory.getCglibProxy(o);
                    }
                }

                map.put(entry.getKey(),o);
            }


        }  catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

    }


    // 任务二：对外提供获取实例对象的接口（根据id获取）
    public static  Object getBean(String id) {
        return map.get(id);
    }

}
